/*  
  -- The Lime II Project -- 

  A tuplespaces-based middleware for coordinating agents and mobile hosts.
  Copyright (C) 2005.
  Gian Pietro Picco, Amy L. Murphy, Lorenzo Bellini.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

package lime2.ca;
import lime2.*;

import java.io.Serializable;
import java.util.HashSet;

/**
 * A testing-oriented (decorator) communication adapter that prints messages to the screen. It decorates the behavior 
 * of another ICommunicationAdapter by attaching to it the printing of messages. 
 *
 * @author Gian Pietro Picco
 * @author Amy Murphy
 * @author Lorenzo Bellini 
 */

public class MsgTestCA implements ICommunicationAdapter, LimeConstants 
{
 // private member: delegated ICommunicationAdapter (default is "null" - it just prints messages)	
 private ICommunicationAdapter dac = null;

 /**
  * Constructor method, just for printing messages.
  */
 public MsgTestCA() 
 {
  // empty constructor	
 }
 
 /**
  * Constructor method.
  * 
  * @param dac concrete communication adapter to decorate with the printing of messages; pass <code>null<\code> if
  * you just want to print messages; please note that another MsgTestCA as concrete CA is automatically discarded
  */ 
 public MsgTestCA(ICommunicationAdapter dac)
 {
  if (!(dac instanceof MsgTestCA)) this.dac = dac;	
 }
 
 /**
  * This method must be called before the communication adapter is used; it performs all the necessary initializations
  * (i.e. starting thread/s, establishing permanent connections, etc..) 
  * 
  * @throws LimeCommunicationException
  */
 public void init() throws LimeCommunicationException 
 {
  System.out.println("C-Adapter: init [" + (dac == null ? this.getClass().getName() : dac.getClass().getName()) + "]");
  if (dac != null) 
  try { dac.init(); } catch (LimeCommunicationException lce) { printFailureMsg(lce); throw lce; }
 }
		
 /**
  * Enables this host to join the system. The serializable object may serve to provide startup information for the 
  * joining process (i.e. a host to attach to in a dispatching tree). Please note that communication exceptions are 
  * not thrown; when this method is invoked, it is guaranteed that the LimeServer will join the system as soon as 
  * possible.
  * 
  * @param info startup information for the joining process
  */	
 public void joinSystem(Serializable info)  
 {
  System.out.println("C-Adapter: joins system");	
  if (dac != null) dac.joinSystem(info); 
 }
 
 /** 
  * Enables this host to leave the system. Please note that communication exceptions are not thrown; when this method
  * is invoked, it is guaranteed that the LimeServer will eventually leave the system. 
  */
 public void leaveSystem() 
 {
  System.out.println("C-Adapter: leaves system");
  if (dac != null) dac.leaveSystem(); 
 }

 /**
  * Declares that from now on this node is interested in everything that concerns a specific tuplespace. Please note 
  * that communication exceptions are not thrown; when this method is invoked, it is guaranteed that the LimeServer 
  * will join the group as soon as possible.
  * 
  * @param name name of the tuplespace we are interested in
  */ 
 public void joinGroup(String name) 
 {
  System.out.println("C-Adapter: joins group <" + name + ">");
  if (dac != null) dac.joinGroup(name);  
 }
	 
 /**
  * Declares that from now on this node is uninterested in everything that concerns a specific tuplespace. Please note
  * that communication exceptions are not thrown; when this method is invoked, it is guaranteed that the LimeServer 
  * will eventually leave the group.
  * 
  * @param name name of the tuplespace we are no more interested in
  */ 
 public void leaveGroup(String name)  
 {
  System.out.println("C-Adapter: leaves group <" + name + ">");	
  if (dac != null) dac.leaveGroup(name); 
 }

 /**
  * Sends an operation request to all the group members.
  * 
  * @param name name of the destination tuplespace 
  * @param d operation descriptor
  * @throws LimeCommunicationException
  */
 public void sendOp(String name, RemoteOp d) throws LimeCommunicationException 
 {
  System.out.println("C-Adapter: sends op " + d.toString() + " to <" + name + ">");
  if (dac != null) 
  try { dac.sendOp(name, d); } catch (LimeCommunicationException lce) { printFailureMsg(lce); throw lce; }
 }

 /**
  * Sends an operation request to a specific host.
  * 
  * @param host destination host
  * @param d operation descriptor
  * @throws LimeCommunicationException
  */
 public void sendOp(LimeServerID host, RemoteOp d) throws LimeCommunicationException 
 {
  System.out.println("C-Adapter: sends op " + d.toString() + " to <" + host + ">");		
  if (dac != null) 
  try { dac.sendOp(host, d); } catch (LimeCommunicationException lce) { printFailureMsg(lce); throw lce; }
 }

 /**
  * Sends a reaction registration request to all group members.
  * 
  * @param name name of the destination tuplespace 
  * @param d operation descriptor
  * @throws LimeCommunicationException
  */
 public void sendReaction(String name, RemoteOp d) throws LimeCommunicationException 
 {
  System.out.println("C-Adapter: sends reaction " + d.toString() + " to <" + name + ">");		
  if (dac != null) 
  try { dac.sendReaction(name, d); } catch (LimeCommunicationException lce) { printFailureMsg(lce); throw lce; }
 }

 /**
  * Sends a reaction registration request to a specific host.
  * 
  * @param host destination host
  * @param d operation descriptor
  * @throws LimeCommunicationException
  */
 public void sendReaction(LimeServerID host, RemoteOp d) throws LimeCommunicationException 
 {
  System.out.println("C-Adapter: sends reaction " + d.toString() + " to <" + host + ">");		
  if (dac != null) 
  try { dac.sendReaction(host, d); } catch (LimeCommunicationException lce) { printFailureMsg(lce); throw lce; }
 }
 
 /**
  * Allows to bind a message to a previous operation request (i.e, to gather results).
  * 
  * @param host destination host
  * @param d operation descriptor
  * @throws LimeCommunicationException
  */
 public void sendReply(LimeServerID host, RemoteOp d) throws LimeCommunicationException 
 {
  System.out.println("C-Adapter: sends reply " + d.toString() + " to <" + host + ">");	
  if (dac != null) 
  try { dac.sendReply(host, d); } catch (LimeCommunicationException lce) { printFailureMsg(lce); throw lce; }
 }
	
 /**
  * Returns a received RemoteOp (FIFO order, blocking).
  * 
  * @return RemoteOp
  */
 public RemoteOp getNextOp()
 {
  if (dac == null) //.. semantics requires to block forever ! 
  	 synchronized(this) { try { wait(); } catch (InterruptedException ie) { ie.printStackTrace(); } }
  RemoteOp ret = dac.getNextOp(); 
  System.out.println("C-Adapter: received " + ret.toString() + " from <" + ret.getSourceString() + ">");
  return ret;
 }
 
 /**
  * Deactivates the communication layer.
  */
 public void shutdown()
 {
  System.out.println("C-Adapter: shutdown");	
  if (dac != null) dac.shutdown();	
 }
 
 /**
  * Returns whether an host is engaged.
  * 
  * @param host
  * @return <code>true</code> or <code>false</code>
  */
 public boolean queryHost(LimeServerID host)
 {
  boolean ret = false;	
  if (dac != null) ret = dac.queryHost(host);
  System.out.println("C-Adapter: queries host <" + host + "> [" + ret + "]");
  return ret;
 }
 
 /**
  * Adds a new (discovered) host.
  * 
  * @param host
  */
 public void addHost(LimeServerID host)
 {
  System.out.println("C-Adapter: adds host <" + host + ">");	
  if (dac != null) dac.addHost(host);	
 }
  
 /**
  * Removes a (probable) dead host.
  * 
  * @param host
  */
 public void removeHost(LimeServerID host)
 {
  System.out.println("C-Adapter: removes host <" + host + ">");		
  if (dac != null) dac.removeHost(host);	
 }
 
 // prints "communication failure" messages 
 private void printFailureMsg(LimeCommunicationException lce)
 {
  System.out.println("C-Adapter: failure (" + Translator.translateFailure(lce.getFailureType()) + ")");	
 }

@Override
public HashSet<LimeServerID> multicast(LimeServerID[] hosts, RemoteOp d)
		throws LimeCommunicationException {
	return null;
	
}

@Override
public HashSet<LimeServerID> multicast(RemoteOp d) throws LimeCommunicationException {
	return null;
	
}
 
}
